package com.sloth.bear.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sloth.bear.dto.entity.Category;
import com.sloth.bear.dto.entity.Todo;
import com.sloth.bear.dto.request.TodoListRequest;
import com.sloth.bear.dto.request.TodoRequest;
import com.sloth.bear.dto.vo.TodoVo;
import com.sloth.bear.mapper.CategoryMapper;
import com.sloth.bear.mapper.TodoMapper;
import com.sloth.bear.service.TodoService;
import com.sloth.bear.util.AssertUtils;
import com.sloth.bear.util.BaseHelper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 待办事项服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TodoServiceImpl extends ServiceImpl<TodoMapper, Todo> implements TodoService {

    private final CategoryMapper categoryMapper;

    @Override
    public TodoVo createTodo(TodoRequest request) {
        Todo todo = BaseHelper.r2t(request, Todo.class);
        if (todo.getStatus() == null) {
            todo.setStatus("todo");
        }
        boolean result = save(todo);
        AssertUtils.isTrue(result, "待办事项创建失败");
        return BaseHelper.r2t(todo, TodoVo.class);
    }

    @Override
    public List<TodoVo> listTodo(TodoListRequest request) {
        List<Todo> todoList = list(Wrappers.<Todo>lambdaQuery()
                .isNull(Long.valueOf(-1).equals(request.getCategoryId()), Todo::getCategoryId)
                .eq(request.getCategoryId() != null && request.getCategoryId() != -1, Todo::getCategoryId, request.getCategoryId())
                .eq(StringUtils.isNotBlank(request.getSearch()), Todo::getTitle, request.getSearch())
                .eq(request.getIsFavorite() != null, Todo::getIsFavorite, request.getIsFavorite())
                .ne(Boolean.FALSE.equals(request.getIsCompleted()), Todo::getStatus, "completed")
                // -1 代表查询所有星级 > 0 的数据
                .gt(Integer.valueOf(-1).equals(request.getRating()), Todo::getRating, 0)
                .eq(request.getRating() != null && request.getRating() != -1, Todo::getRating, request.getRating())
                .orderByDesc(Todo::getIsTop)
                .orderByDesc(Todo::getCreatedTime));
        if (CollectionUtils.isEmpty(todoList)) {
            return new ArrayList<>();
        }

        Set<Long> categoryIds = todoList.stream().map(Todo::getCategoryId).collect(Collectors.toSet());
        List<Category> categories = categoryMapper.selectBatchIds(categoryIds);
        Map<Long, String> categoryMap = categories.stream().collect(Collectors.toMap(Category::getId, Category::getName));

        return todoList.stream()
                .sorted(Comparator.comparingInt((Todo p) -> p.getStatus().equals("completed") ? 1 : 0)
                        .thenComparing(todoList::indexOf))
                .map(o -> {
                    TodoVo vo = BaseHelper.r2t(o, TodoVo.class);
                    vo.setCategoryName(categoryMap.get(o.getCategoryId()));
                    return vo;
                })
                .toList();
    }

    @Override
    public TodoVo detailsTodo(Long id) {
        Todo todo = getById(id);
        AssertUtils.notNull(todo, "待办事项不存在");
        return BaseHelper.r2t(todo, TodoVo.class);
    }

    @Override
    public TodoVo updateTodo(Long id, TodoRequest request) {
        Todo todo = getById(id);
        AssertUtils.notNull(todo, "待办事项不存在");

        String oldStatus = todo.getStatus();
        BeanUtils.copyProperties(request, todo);

        if ("completed".equals(request.getStatus()) && !"completed".equals(oldStatus)) {
            todo.setCompletedAt(LocalDateTime.now());
        } else if (!"completed".equals(request.getStatus()) && "completed".equals(oldStatus)) {
            todo.setCompletedAt(null);
        }

        boolean result = updateById(todo);
        AssertUtils.isTrue(result, "待办事项更新失败");
        return BaseHelper.r2t(todo, TodoVo.class);
    }

    @Override
    public Boolean deleteTodo(Long id) {
        Todo todo = getById(id);
        AssertUtils.notNull(todo, "待办事项不存在");
        return removeById(id);
    }
}